﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Dominio.Repositorios;
using Moq;

namespace Dominio.Tests.Unitarios {
    [TestClass]
    public class ContaTeste {
        public IUsuarioRepository _usuarioRepository;

        public ContaTeste() {
            var usuarioRepositoryMock = new Mock<IUsuarioRepository>();
            usuarioRepositoryMock.Setup(m => m.Obtem(1))
                               .Returns(MontaUsuario());
            _usuarioRepository = usuarioRepositoryMock.Object;
        }

        [TestMethod]
        public void sacando_um_valor_da_conta_o_saldo_eh_subtraido_este() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);

            conta.Deposita(30m, null);
            conta.Saca(50.2m, null);

            Assert.IsTrue(conta.Saldo == (decimal)-20.2);
        }

        [TestMethod]
        public void sacando_um_valor_da_conta_positivo_este_eh_convertido_para_negativo() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);

            conta.Saca((decimal)50.2, null);

            Assert.IsTrue(conta.Saldo == (decimal)-50.2);
        }

        [TestMethod]
        public void apagando_uma_conta_do_usuario_sua_lista_deve_diminuir_de_quantidade() {
            var usuario = _usuarioRepository.Obtem(1);

            usuario.ApagaConta(1);

            Assert.IsTrue(usuario.Contas.Count == 0);
        }

        [TestMethod]
        public void depositando_um_valor_na_conta_seu_saldo_eh_somado_com_este() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);

            conta.Deposita(30m, null);
            conta.Deposita(50.2m, null);

            Assert.IsTrue(conta.Saldo == (decimal)80.2);
        }

        [TestMethod]
        public void depositando_um_valor_negativo_na_conta_este_eh_convertido_para_positivo() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);

            conta.Deposita((decimal)-50.2, null);

            Assert.IsTrue(conta.Saldo == (decimal)50.2);
        }

        [TestMethod]
        public void fazendo_uma_agendamento_mensal_de_3_lancamentos_deve_gerar_uma_diferenca_de_30_dias_entre_eles() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);
            var tipoContrato = TipoContrato.MENSAL;

            conta.AgendaDeposito(50, DateTime.Now, 3, null, tipoContrato);
            var agendamentos = (List<Lancamento>)Helper.ObtemPropriedade(conta, "_Lancamentos");
            Assert.IsTrue(agendamentos[0].Data.Month == agendamentos[1].Data.AddMonths(-1).Month);
            Assert.IsTrue(agendamentos[1].Data.Month == agendamentos[2].Data.AddMonths(-1).Month);
            Assert.IsTrue(agendamentos[2].Data == agendamentos.LastOrDefault().Contrato.Final);
        }

        [TestMethod]
        public void fazendo_uma_agendamento_anual_de_3_lancamentos_deve_gerar_uma_diferenca_de_30_dias_entre_eles() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);
            var tipoContrato = TipoContrato.ANUAL;

            conta.AgendaDeposito(50, DateTime.Now, 3, null, tipoContrato);
            var agendamentos = (List<Lancamento>)Helper.ObtemPropriedade(conta, "_Lancamentos");
            Assert.IsTrue(agendamentos[0].Data.Year == agendamentos[1].Data.Year - 1);
            Assert.IsTrue(agendamentos[1].Data.Year == agendamentos[2].Data.Year - 1);
        }

        [TestMethod]
        public void fazendo_uma_agendamento_mensal_de_3_repeticoes_este_deve_gerar_3_lancamentos() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);
            var tipoContrato = TipoContrato.MENSAL;

            conta.AgendaDeposito(50, DateTime.Now, 3, null, tipoContrato);
            var agendamentos = (List<Lancamento>)Helper.ObtemPropriedade(conta, "_Lancamentos");
            Assert.IsTrue(agendamentos.Count == 3);
        }

        [TestMethod]
        public void fazendo_uma_agendamento_mensal_de_3_repeticoes_estes_nao_alteram_o_saldo_da_conta() {
            var usuario = _usuarioRepository.Obtem(1);
            var conta = usuario.ObtemConta(1);
            var tipoContrato = TipoContrato.MENSAL;

            conta.AgendaDeposito(50, DateTime.Now, 3, null, tipoContrato);
            Assert.IsTrue(conta.Saldo == 0);
        }

        private Usuario MontaUsuario() {
            var usuario = new Usuario(string.Empty, string.Empty, string.Empty);            
            var conta = new Conta(0, string.Empty, usuario);
            Helper.IncluiPropriedade(conta, "Id", 1);
            Helper.IncluiPropriedade(usuario, "Contas", new List<Conta> { conta });

            return usuario;
        }
    }
}
